package xyz.magicjson.core.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import xyz.magicjson.core.annotation.ESBEndpoint;
import xyz.magicjson.core.exception.ESBException;
import xyz.magicjson.core.model.Message;
import xyz.magicjson.core.model.Result;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.UUID;

/**
 * ESB端点切面，用于拦截所有标记了@ESBEndpoint注解的方法。
 * 在方法执行前后添加日志记录、参数验证、异常处理等功能。
 */
@Slf4j
@Aspect
@Order(1)
@Component
public class ESBEndpointAspect {

    /**
     * 定义切点，拦截所有标记了@ESBEndpoint注解的方法
     */
    @Pointcut("@annotation(xyz.magicjson.core.annotation.ESBEndpoint)")
    public void esbEndpointPointcut() {
    }

    /**
     * 环绕通知，在方法执行前后添加处理逻辑
     *
     * @param joinPoint 连接点
     * @return 方法执行结果
     * @throws Throwable 执行过程中可能抛出的异常
     */
    @Around("esbEndpointPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        // 获取注解
        ESBEndpoint esbEndpoint = method.getAnnotation(ESBEndpoint.class);
        
        // 获取请求ID
        String requestId = UUID.randomUUID().toString();
        
        // 记录请求日志
        if (esbEndpoint.enableLogging()) {
            log.info("ESB请求开始 - 服务名称: {}, 请求ID: {}, 参数: {}", 
                    getServiceName(esbEndpoint, method), 
                    requestId, 
                    Arrays.toString(joinPoint.getArgs()));
        }
        
        // 开始时间
        long startTime = System.currentTimeMillis();
        
        try {
            // 参数验证和加密处理
            Object[] args = processRequestParams(joinPoint.getArgs(), esbEndpoint);
            
            // 执行方法
            Object result = joinPoint.proceed(args);
            
            // 处理响应
            result = processResponse(result, requestId);
            
            // 记录响应日志
            if (esbEndpoint.enableLogging()) {
                log.info("ESB请求完成 - 服务名称: {}, 请求ID: {}, 耗时: {}ms", 
                        getServiceName(esbEndpoint, method), 
                        requestId, 
                        System.currentTimeMillis() - startTime);
            }
            
            return result;
        } catch (Exception e) {
            // 记录错误日志
            log.error("ESB请求异常 - 服务名称: {}, 请求ID: {}, 异常: {}", 
                    getServiceName(esbEndpoint, method), 
                    requestId, 
                    e.getMessage(), e);
            
            // 异常处理
            return handleException(e, requestId);
        }
    }
    
    /**
     * 获取服务名称
     *
     * @param esbEndpoint 注解
     * @param method      方法
     * @return 服务名称
     */
    private String getServiceName(ESBEndpoint esbEndpoint, Method method) {
        return esbEndpoint.name().isEmpty() ? method.getName() : esbEndpoint.name();
    }
    
    /**
     * 处理请求参数
     *
     * @param args        参数数组
     * @param esbEndpoint 注解
     * @return 处理后的参数数组
     */
    private Object[] processRequestParams(Object[] args, ESBEndpoint esbEndpoint) {
        // 如果启用加密，则对参数进行解密
        if (esbEndpoint.enableEncryption()) {
            // TODO: 实现参数解密逻辑
        }
        
        // TODO: 参数验证逻辑
        
        return args;
    }
    
    /**
     * 处理响应
     *
     * @param result    原始响应
     * @param requestId 请求ID
     * @return 处理后的响应
     */
    private Object processResponse(Object result, String requestId) {
        // 如果结果已经是Result类型，则直接返回
        if (result instanceof Result) {
            return ((Result<?>) result).requestId(requestId);
        }
        
        // 如果结果是Message类型，则直接返回
        if (result instanceof Message) {
            return result;
        }
        
        // 其他类型，包装为Result
        return Result.success(result).requestId(requestId);
    }
    
    /**
     * 处理异常
     *
     * @param e         异常
     * @param requestId 请求ID
     * @return 异常响应
     */
    private Result<?> handleException(Exception e, String requestId) {
        if (e instanceof ESBException) {
            ESBException esbException = (ESBException) e;
            return Result.error(esbException.getCode(), esbException.getMessage()).requestId(requestId);
        }
        
        return Result.error(500, "服务内部错误: " + e.getMessage()).requestId(requestId);
    }
} 